package ups.Analysis;

import ups.Common.Departure;
import ups.Common.Port;
import ups.Common.Ship;
import ups.Schedule.ScheduleItem;
import ups.Schedule.ScheduleItemComparator;
import ups.Schedule.ScheduleTime;
import ups.Common.ShipComparator;
import ups.MapParse.Point;
import ups.Common.DataImporter;
import ups.Database.LateDatabase;
import ups.Database.PortDatabase;
import ups.Database.ScheduleDatabase;
import ups.Database.ShipDatabase;
import ups.Schedule.ScheduleBuilder;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Hashtable;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Collections;
import java.util.Date;
import java.io.File;

import ups.Common.ArgumentParser;
/* This class analyzes ship location records and the schedule to find out WHEN a ship is late. It stores a listing of times when the ship was supposed to leave and when it actually left for each schedule position of the week.*/

public class TardyShipAnalysis extends DataImporter {
	
	public static void main( String[] args ) {
		ArgumentParser parser = new ArgumentParser( args );
		
		/* Need a DAY to analyze, a SCHEDULE to base that off of, and a LIST of Port Locations */
		Date day = null;
		try {
			day = getDateFormat().parse( parser.valueForKey( "--day" ));
		} catch ( Exception ex ) {
			ex.printStackTrace();
		}
		
		String shipName = parser.valueForKey("--ship");
		
		System.out.println( day.toString() );

		ShipDatabase shipDB = new ShipDatabase( DBHostName ,DBPort, DBName, DBUsername, DBPass);
		ArrayList<Ship> ships = shipDB.getShipsForDay( shipName, day );
		PortDatabase portDB = new PortDatabase( DBHostName ,DBPort, DBName, DBUsername, DBPass );
		
		if( ships.size() <= 10 ) {
			return;
		}
		
		TardyShipAnalysis analysis = new TardyShipAnalysis( ships , portDB.getPorts() );
	}
	
	private static SimpleDateFormat format = new SimpleDateFormat("DDD-yyyy" );
	public static SimpleDateFormat getDateFormat() {
		return format;
	}
	
	private ArrayList<Port> ports;
	
	
	// Ship and Schedule need to be sorted by date.
	public TardyShipAnalysis( ArrayList<Ship> ships, ArrayList<Port> ports ) {
		super( null );
		
		this.ports = ports;
		
		// Set up Database
		LateDatabase lateDB = new LateDatabase( DBHostName ,DBPort, DBName, DBUsername, DBPass );
		
		Calendar cal = Calendar.getInstance();
		cal.setTime( ships.get( 0 ).getDate() );
		System.out.println( ships.get( 0 ).getName() + " on " +  cal.get( Calendar.DAY_OF_YEAR ));
		
		
		// Find Ship Leaving Events
		ArrayList<LeavingShip> leaving = new ArrayList<LeavingShip>();
		int shipIndex = 0;
		for( shipIndex = 0; shipIndex < ships.size() - 1; shipIndex++ ) {
			Ship currentLocation = ships.get( shipIndex );
			Ship nextLocation = ships.get( shipIndex + 1 );
			if (currentLocation == null ) {
				//System.out.println( shipIndex + " is null ");
			}
			if( !currentLocation.isMoving() && nextLocation.isMoving() ) {
				Port ourPort = closestPort( currentLocation );
			//	System.out.println( ourPort.toString() );
				leaving.add( new LeavingShip( nextLocation, ourPort ));
				//BUG: Guessing the wrong port for some reason ( gueses Fauntleroy when it should guess Seattle!? )
			}
		}

		// Get the route for these stops and times
		LeavingShip firstEvent = leaving.get( 0 );
		LeavingShip secondEvent = leaving.get( 1 );
		ScheduleDatabase schedDB = new ScheduleDatabase( DBHostName ,DBPort, DBName, DBUsername, DBPass );
		int routeID = schedDB.getRoute( firstEvent.getShip().getDate(), firstEvent.getPort().getName(), secondEvent.getPort().getName() );
		ArrayList<ScheduleItem> schedule = schedDB.getSchedule( routeID );
		
		
		int departureIndex = 0;
	//	System.out.println( leaving.size() );
	//	System.out.println( schedule.size() );
		if( leaving.size() != schedule.size() ) {
			System.out.println("WRONG SIZES: Debugging Follows...");
			System.out.println("Ship Leaving Events " + leaving.size() + ":");
			int index = 0;
			for( LeavingShip s: leaving ) {
				System.out.println( index +  " : " + s.toString() );
				index++;
			}
			
			System.out.println("Schedule " + schedule.size() + ":");
			index = 0;
			for( ScheduleItem sched : schedule ) {
				System.out.println( index + " : " + sched.toString() );
				index++;
			}
			
			System.exit(-1);
			
		}
		
		for( departureIndex = 0; departureIndex < schedule.size(); departureIndex++ ) {
			ScheduleItem item = schedule.get( departureIndex );
			LeavingShip ship = leaving.get( departureIndex );
			//System.out.println( ship.toString() + " vs. " + item.toString() );
			if(! item.getLeavingFrom().equals( ship.getPort().getName()) ) {
				System.out.println( item.getLeavingFrom() + " doesn't match " + ship.getPort().getName());
			}
			
			Date shipDate = ship.getShip().getDate();
			ScheduleTime schedTime = item.getTime();
			int minutesLate = (60 * (shipDate.getHours() - schedTime.getHours()) + ( shipDate.getMinutes() - schedTime.getMinutes() ));
		//	System.out.println( minutesLate + " minutes late" );
			
			System.out.println( schedTime.getHours() + ":" + schedTime.getMinutes() + "\t" + minutesLate);
			//ture(String shipName, String portName, Date date, Date scheduled_time, Date actual_time) {
			Date scheduled = new Date();
			scheduled.setHours( schedTime.getHours() );
			scheduled.setMinutes( schedTime.getMinutes() );
			scheduled.setSeconds( 0 );
			Departure depart = new Departure( ship.getShip().getName(), ship.getPort().getName(), routeID, ship.getShip().getDate(), scheduled, ship.getShip().getDate() );
			
		//	System.out.println("PUT");
			lateDB.put( depart );
		}
	}
	
	private Port getPortForName( String name ) {
		for( Port p : this.ports ) {
			if( p.getName().equals( name )) {
				return p;
			}
		}
		return null;
	}
	
	private Port closestPort( Ship aShip ) {
		//System.out.println( "Finding nearest port to " + aShip.toString() );
		double closestDistance = 1000000.0f;
	//	Enumeration keys = portLoc.keys();
		Port closestPort = null;
		for( Port port : this.ports ) {
	//	while( keys.hasMoreElements() ) {
		//	String key = (String)keys.nextElement();
			double distance = aShip.getLocation().distanceFrom( port.getLocation() );
			if( distance < closestDistance ) {
				closestDistance = distance;
				closestPort = port;
			///	System.out.println( "Closest port " + closestPort.toString() + " at distance " + closestDistance );
			}
		}
		
	//	System.out.println("\n\n");
		return closestPort;
	}
	
	private boolean near( Ship aShip, Point aPoint ) {
		double distance = aShip.getLocation().distanceFrom( aPoint );
		if( distance <= 3 ) {
			return true;
		}
		
		return false;
	}
	
}
